using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using PickGold.Charting.ChartTypes;

namespace PickGold.Charting
{
	[SRDescription("DescriptionAttributeSmartLabels_SmartLabels")]
	internal class SmartLabel
	{
		internal bool checkAllCollisions;
		internal int markersCount;
		internal ArrayList smartLabelsPositions;

		internal virtual void AddMarkersPosition(CommonElements common, ChartArea area)
		{
			if ((this.smartLabelsPositions.Count == 0) && (area != null))
			{
				ChartTypeRegistry chartTypeRegistry = common.ChartTypeRegistry;
				foreach (Series series in common.DataManager.Series)
				{
					if (((series.ChartArea == area.Name) && series.SmartLabelStyle.Enabled) && !series.SmartLabelStyle.IsMarkerOverlappingAllowed)
					{
						chartTypeRegistry.GetChartType(series.ChartTypeName).AddSmartLabelMarkerPositions(common, area, series, this.smartLabelsPositions);
					}
				}
				foreach (Axis axis in area.Axes)
				{
					if ((axis.ScaleBreakStyle.Spacing > 0.0) && (axis.ScaleSegments.Count > 0))
					{
						for (int i = 0; i < (axis.ScaleSegments.Count - 1); i++)
						{
							RectangleF breakLinePosition = axis.ScaleSegments[i].GetBreakLinePosition(common.graph, axis.ScaleSegments[i + 1]);
							breakLinePosition = common.graph.GetRelativeRectangle(breakLinePosition);
							if (this.smartLabelsPositions == null)
							{
								this.smartLabelsPositions = new ArrayList();
							}
							this.smartLabelsPositions.Add(breakLinePosition);
						}
					}
				}
			}
		}

		internal void AddSmartLabelPosition(ChartGraphics graph, PointF position, SizeF size, StringFormat format)
		{
			RectangleF ef = this.GetLabelPosition(graph, position, size, format, false);
			if (this.smartLabelsPositions == null)
			{
				this.smartLabelsPositions = new ArrayList();
			}
			this.smartLabelsPositions.Add(ef);
		}

		internal PointF AdjustSmartLabelPosition(CommonElements common, ChartGraphics graph, ChartArea area, SmartLabelStyle smartLabelStyle, PointF labelPosition, SizeF labelSize, StringFormat format, PointF markerPosition, SizeF markerSize, LabelAlignmentStyles labelAlignment)
		{
			return this.AdjustSmartLabelPosition(common, graph, area, smartLabelStyle, labelPosition, labelSize, format, markerPosition, markerSize, labelAlignment, false);
		}

		internal PointF AdjustSmartLabelPosition(CommonElements common, ChartGraphics graph, ChartArea area, SmartLabelStyle smartLabelStyle, PointF labelPosition, SizeF labelSize, StringFormat format, PointF markerPosition, SizeF markerSize, LabelAlignmentStyles labelAlignment, bool checkCalloutLineOverlapping)
		{
			if (smartLabelStyle.Enabled)
			{
				bool flag2 = this.smartLabelsPositions.Count == 0;
				this.AddMarkersPosition(common, area);
				if (flag2)
				{
					this.markersCount = this.smartLabelsPositions.Count;
				}
				if ((this.IsSmartLabelCollide(common, graph, area, smartLabelStyle, labelPosition, labelSize, markerPosition, format, labelAlignment, checkCalloutLineOverlapping) && ((this.FindNewPosition(common, graph, area, smartLabelStyle, ref labelPosition, labelSize, format, markerPosition, ref markerSize, ref labelAlignment, checkCalloutLineOverlapping) || (labelAlignment == LabelAlignmentStyles.BottomLeft)) || (((labelAlignment == LabelAlignmentStyles.BottomRight) || (labelAlignment == LabelAlignmentStyles.TopLeft)) || (labelAlignment == LabelAlignmentStyles.TopRight)))) && !labelPosition.IsEmpty)
				{
					this.DrawCallout(common, graph, area, smartLabelStyle, labelPosition, labelSize, format, markerPosition, markerSize, labelAlignment);
				}
				this.AddSmartLabelPosition(graph, labelPosition, labelSize, format);
			}
			return labelPosition;
		}

		private PointF CalculatePosition(LabelAlignmentStyles labelAlignment, PointF markerPosition, SizeF sizeMarker, SizeF sizeFont, ref StringFormat format)
		{
			format.Alignment = StringAlignment.Near;
			format.LineAlignment = StringAlignment.Center;
			PointF tf = new PointF(markerPosition.X, markerPosition.Y);
			LabelAlignmentStyles styles = labelAlignment;
			if (styles <= LabelAlignmentStyles.TopLeft)
			{
				switch (styles)
				{
					case LabelAlignmentStyles.Top:
						format.Alignment = StringAlignment.Center;
						tf.Y -= sizeMarker.Height / 1.75f;
						tf.Y -= sizeFont.Height / 2f;
						return tf;

					case LabelAlignmentStyles.Bottom:
						format.Alignment = StringAlignment.Center;
						tf.Y += sizeMarker.Height / 1.75f;
						tf.Y += sizeFont.Height / 2f;
						return tf;

					case (LabelAlignmentStyles.Bottom | LabelAlignmentStyles.Top):
						return tf;

					case LabelAlignmentStyles.Right:
						tf.X += sizeMarker.Height / 1.75f;
						return tf;

					case LabelAlignmentStyles.Left:
						format.Alignment = StringAlignment.Far;
						tf.X -= sizeMarker.Height / 1.75f;
						return tf;

					case LabelAlignmentStyles.TopLeft:
						format.Alignment = StringAlignment.Far;
						tf.X -= sizeMarker.Height / 1.75f;
						tf.Y -= sizeMarker.Height / 1.75f;
						tf.Y -= sizeFont.Height / 2f;
						return tf;
				}
				return tf;
			}
			if (styles <= LabelAlignmentStyles.BottomLeft)
			{
				switch (styles)
				{
					case LabelAlignmentStyles.TopRight:
						tf.X += sizeMarker.Height / 1.75f;
						tf.Y -= sizeMarker.Height / 1.75f;
						tf.Y -= sizeFont.Height / 2f;
						return tf;

					case LabelAlignmentStyles.BottomLeft:
						format.Alignment = StringAlignment.Far;
						tf.X -= sizeMarker.Height / 1.75f;
						tf.Y += sizeMarker.Height / 1.75f;
						tf.Y += sizeFont.Height / 2f;
						return tf;
				}
				return tf;
			}
			switch (styles)
			{
				case LabelAlignmentStyles.BottomRight:
					tf.X += sizeMarker.Height / 1.75f;
					tf.Y += sizeMarker.Height / 1.75f;
					tf.Y += sizeFont.Height / 2f;
					return tf;

				case LabelAlignmentStyles.Center:
					format.Alignment = StringAlignment.Center;
					break;
			}
			return tf;
		}

		internal virtual void DrawCallout(CommonElements common, ChartGraphics graph, ChartArea area, SmartLabelStyle smartLabelStyle, PointF labelPosition, SizeF labelSize, StringFormat format, PointF markerPosition, SizeF markerSize, LabelAlignmentStyles labelAlignment)
		{
			RectangleF absoluteRectangle = graph.GetAbsoluteRectangle(this.GetLabelPosition(graph, labelPosition, labelSize, format, true));
			Pen pen = new Pen(smartLabelStyle.CalloutLineColor, (float)smartLabelStyle.CalloutLineWidth);
			pen.DashStyle = graph.GetPenStyle(smartLabelStyle.CalloutLineDashStyle);
			if (smartLabelStyle.CalloutStyle == LabelCalloutStyle.Box)
			{
				if (smartLabelStyle.CalloutBackColor != Color.Transparent)
				{
					using (Brush brush = new SolidBrush(smartLabelStyle.CalloutBackColor))
					{
						graph.FillRectangle(brush, absoluteRectangle);
					}
				}
				graph.DrawRectangle(pen, absoluteRectangle.X, absoluteRectangle.Y, absoluteRectangle.Width, absoluteRectangle.Height);
			}
			else if (smartLabelStyle.CalloutStyle == LabelCalloutStyle.Underlined)
			{
				if (labelAlignment == LabelAlignmentStyles.Right)
				{
					graph.DrawLine(pen, absoluteRectangle.X, absoluteRectangle.Top, absoluteRectangle.X, absoluteRectangle.Bottom);
				}
				else if (labelAlignment == LabelAlignmentStyles.Left)
				{
					graph.DrawLine(pen, absoluteRectangle.Right, absoluteRectangle.Top, absoluteRectangle.Right, absoluteRectangle.Bottom);
				}
				else if (labelAlignment == LabelAlignmentStyles.Bottom)
				{
					graph.DrawLine(pen, absoluteRectangle.X, absoluteRectangle.Top, absoluteRectangle.Right, absoluteRectangle.Top);
				}
				else
				{
					graph.DrawLine(pen, absoluteRectangle.X, absoluteRectangle.Bottom, absoluteRectangle.Right, absoluteRectangle.Bottom);
				}
			}
			PointF absolutePoint = graph.GetAbsolutePoint(labelPosition);
			if (labelAlignment == LabelAlignmentStyles.Top)
			{
				absolutePoint.Y = absoluteRectangle.Bottom;
			}
			else if (labelAlignment == LabelAlignmentStyles.Bottom)
			{
				absolutePoint.Y = absoluteRectangle.Top;
			}
			if ((smartLabelStyle.CalloutStyle == LabelCalloutStyle.Underlined) && (((labelAlignment == LabelAlignmentStyles.TopLeft) || (labelAlignment == LabelAlignmentStyles.TopRight)) || ((labelAlignment == LabelAlignmentStyles.BottomLeft) || (labelAlignment == LabelAlignmentStyles.BottomRight))))
			{
				absolutePoint.Y = absoluteRectangle.Bottom;
			}
			if (smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Arrow)
			{
				pen.StartCap = LineCap.Custom;
				pen.CustomStartCap = new AdjustableArrowCap(pen.Width + 2f, pen.Width + 3f, true);
			}
			else if (smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Diamond)
			{
				pen.StartCap = LineCap.DiamondAnchor;
			}
			else if (smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Round)
			{
				pen.StartCap = LineCap.RoundAnchor;
			}
			else if (smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Square)
			{
				pen.StartCap = LineCap.SquareAnchor;
			}
			PointF tf2 = graph.GetAbsolutePoint(markerPosition);
			graph.DrawLine(pen, tf2.X, tf2.Y, absolutePoint.X, absolutePoint.Y);
		}

		private bool FindNewPosition(CommonElements common, ChartGraphics graph, ChartArea area, SmartLabelStyle smartLabelStyle, ref PointF labelPosition, SizeF labelSize, StringFormat format, PointF markerPosition, ref SizeF markerSize, ref LabelAlignmentStyles labelAlignment, bool checkCalloutLineOverlapping)
		{
			SizeF empty = SizeF.Empty;
			PointF position = PointF.Empty;
			int index = 0;
			float num2 = 0f;
			bool flag = false;
			LabelAlignmentStyles[] stylesArray = new LabelAlignmentStyles[] { LabelAlignmentStyles.Top, LabelAlignmentStyles.Bottom, LabelAlignmentStyles.Left, LabelAlignmentStyles.Right, LabelAlignmentStyles.TopLeft, LabelAlignmentStyles.TopRight, LabelAlignmentStyles.BottomLeft, LabelAlignmentStyles.BottomRight, LabelAlignmentStyles.Center };
			SizeF relativeSize = graph.GetRelativeSize(new SizeF(1f, 1f));
			bool flag2 = false;
			float num3 = 2f;
			float num4 = (float)Math.Min(smartLabelStyle.MinMovingDistance, smartLabelStyle.MaxMovingDistance);
			float num5 = (float)Math.Max(smartLabelStyle.MinMovingDistance, smartLabelStyle.MaxMovingDistance);
			for (num2 = num4; !flag2 && (num2 <= num5); num2 += num3)
			{
				empty = new SizeF(markerSize.Width + (num2 * (relativeSize.Width * 2f)), markerSize.Height + (num2 * (relativeSize.Height * 2f)));
				index = 0;
				while (index < stylesArray.Length)
				{
					if (((stylesArray[index] != LabelAlignmentStyles.Center) || (num2 == num4)) && ((smartLabelStyle.MovingDirection & stylesArray[index]) == stylesArray[index]))
					{
						position = this.CalculatePosition(stylesArray[index], markerPosition, empty, labelSize, ref format);
						if (!this.IsSmartLabelCollide(common, null, area, smartLabelStyle, position, labelSize, markerPosition, format, stylesArray[index], checkCalloutLineOverlapping))
						{
							flag2 = true;
							flag = num2 != 0f;
							break;
						}
					}
					index++;
				}
			}
			if (flag2)
			{
				markerSize = empty;
				labelPosition = position;
				labelAlignment = stylesArray[index];
			}
			if (!flag2 && smartLabelStyle.IsOverlappedHidden)
			{
				labelPosition = PointF.Empty;
			}
			return (flag && flag2);
		}

		internal RectangleF GetLabelPosition(ChartGraphics graph, PointF position, SizeF size, StringFormat format, bool adjustForDrawing)
		{
			RectangleF empty = RectangleF.Empty;
			empty.Width = size.Width;
			empty.Height = size.Height;
			SizeF relativeSize = SizeF.Empty;
			if (graph != null)
			{
				relativeSize = graph.GetRelativeSize(new SizeF(1f, 1f));
			}
			if (format.Alignment == StringAlignment.Far)
			{
				empty.X = position.X - size.Width;
				if (adjustForDrawing && !relativeSize.IsEmpty)
				{
					empty.X -= 4f * relativeSize.Width;
					empty.Width += 4f * relativeSize.Width;
				}
			}
			else if (format.Alignment == StringAlignment.Near)
			{
				empty.X = position.X;
				if (adjustForDrawing && !relativeSize.IsEmpty)
				{
					empty.Width += 4f * relativeSize.Width;
				}
			}
			else if (format.Alignment == StringAlignment.Center)
			{
				empty.X = position.X - (size.Width / 2f);
				if (adjustForDrawing && !relativeSize.IsEmpty)
				{
					empty.X -= 2f * relativeSize.Width;
					empty.Width += 4f * relativeSize.Width;
				}
			}
			if (format.LineAlignment == StringAlignment.Far)
			{
				empty.Y = position.Y - size.Height;
				return empty;
			}
			if (format.LineAlignment == StringAlignment.Near)
			{
				empty.Y = position.Y;
				return empty;
			}
			if (format.LineAlignment == StringAlignment.Center)
			{
				empty.Y = position.Y - (size.Height / 2f);
			}
			return empty;
		}

		internal virtual bool IsSmartLabelCollide(CommonElements common, ChartGraphics graph, ChartArea area, SmartLabelStyle smartLabelStyle, PointF position, SizeF size, PointF markerPosition, StringFormat format, LabelAlignmentStyles labelAlignment, bool checkCalloutLineOverlapping)
		{
			bool flag = false;
			RectangleF rect = this.GetLabelPosition(graph, position, size, format, false);
			if (((rect.X < 0f) || (rect.Y < 0f)) || ((rect.Bottom > 100f) || (rect.Right > 100f)))
			{
				flag = true;
			}
			if (!flag && (area != null))
			{
				if (area.chartAreaIsCurcular)
				{
					using (GraphicsPath path = new GraphicsPath())
					{
						path.AddEllipse(area.PlotAreaPosition.ToRectangleF());
						if (smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.Partial)
						{
							PointF point = new PointF(rect.X + (rect.Width / 2f), rect.Y + (rect.Height / 2f));
							if (!path.IsVisible(point))
							{
								flag = true;
							}
						}
						else if ((smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.No) && ((!path.IsVisible(rect.Location) || !path.IsVisible(new PointF(rect.Right, rect.Y))) || (!path.IsVisible(new PointF(rect.Right, rect.Bottom)) || !path.IsVisible(new PointF(rect.X, rect.Bottom)))))
						{
							flag = true;
						}
						goto Label_01B6;
					}
				}
				if (smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.Partial)
				{
					PointF pt = new PointF(rect.X + (rect.Width / 2f), rect.Y + (rect.Height / 2f));
					if (!area.PlotAreaPosition.ToRectangleF().Contains(pt))
					{
						flag = true;
					}
				}
				else if ((smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.No) && !area.PlotAreaPosition.ToRectangleF().Contains(rect))
				{
					flag = true;
				}
			}
		Label_01B6: ;
			bool flag2 = (labelAlignment == LabelAlignmentStyles.Center) && !smartLabelStyle.IsMarkerOverlappingAllowed;
			if (this.checkAllCollisions)
			{
				flag2 = false;
			}
			if (!flag && (this.smartLabelsPositions != null))
			{
				int num = -1;
				foreach (RectangleF ef2 in this.smartLabelsPositions)
				{
					num++;
					bool flag3 = ef2.IntersectsWith(rect);
					if ((!flag3 && checkCalloutLineOverlapping) && (num >= this.markersCount))
					{
						PointF tf3 = new PointF(rect.X + (rect.Width / 2f), rect.Y + (rect.Height / 2f));
						if (this.LineIntersectRectangle(ef2, markerPosition, tf3))
						{
							flag3 = true;
						}
					}
					if (flag3)
					{
						if (flag2)
						{
							flag2 = false;
						}
						else
						{
							return true;
						}
					}
				}
			}
			return flag;
		}

		private bool LineIntersectRectangle(RectangleF rect, PointF point1, PointF point2)
		{
			if (point1.X == point2.X)
			{
				if ((point1.X < rect.X) || (point1.X > rect.Right))
				{
					return false;
				}
				if ((point1.Y < rect.Y) && (point2.Y < rect.Y))
				{
					return false;
				}
				if ((point1.Y > rect.Bottom) && (point2.Y > rect.Bottom))
				{
					return false;
				}
				return true;
			}
			if (point1.Y == point2.Y)
			{
				if ((point1.Y < rect.Y) || (point1.Y > rect.Bottom))
				{
					return false;
				}
				if ((point1.X < rect.X) && (point2.X < rect.X))
				{
					return false;
				}
				if ((point1.X > rect.Right) && (point2.X > rect.Right))
				{
					return false;
				}
				return true;
			}
			if ((point1.X < rect.X) && (point2.X < rect.X))
			{
				return false;
			}
			if ((point1.X > rect.Right) && (point2.X > rect.Right))
			{
				return false;
			}
			if ((point1.Y < rect.Y) && (point2.Y < rect.Y))
			{
				return false;
			}
			if ((point1.Y > rect.Bottom) && (point2.Y > rect.Bottom))
			{
				return false;
			}
			if (rect.Contains(point1) || rect.Contains(point2))
			{
				return true;
			}
			PointF pt = CalloutAnnotation.GetIntersectionY(point1, point2, rect.Y);
			if (rect.Contains(pt))
			{
				return true;
			}
			pt = CalloutAnnotation.GetIntersectionY(point1, point2, rect.Bottom);
			if (rect.Contains(pt))
			{
				return true;
			}
			pt = CalloutAnnotation.GetIntersectionX(point1, point2, rect.X);
			if (rect.Contains(pt))
			{
				return true;
			}
			pt = CalloutAnnotation.GetIntersectionX(point1, point2, rect.Right);
			return rect.Contains(pt);
		}

		internal void Reset()
		{
			this.smartLabelsPositions = new ArrayList();
		}
	}
}

